#!/usr/bin/env python3
# -*- coding:utf-8 -*-
## author : cypro666
## date   : 2014.6.1
"""
Define some utilities for debugging and printing errors
"""
import sys
import time
import functools
import traceback
from os import path

__all__ = ['stdtime', 'time_meter', 'classname', 'print_exception', 'run_stdio_flusher']


def stdtime():
    """Return datetime string like 14-06-23 21:56:07"""
    return time.strftime('%y-%m-%d %H:%M:%S')


def time_meter(src=path.basename(__file__)):
    """A time meter decorator, using like @time_meter('some name or title')"""
    def _wrapper(func):
        @functools.wraps(func)
        def _call(*args, **kwargs):
            sys.stdout.write(stdtime() + (' %s : %s started...\n' % (src, _call.__name__)))
            ret = func(*args, **kwargs)
            sys.stdout.write(stdtime() + (' %s : %s finished...\n' % (src, _call.__name__)))
            return ret
        return _call
    return _wrapper


def classname(obj):
    """Return class' name"""
    return str(obj.__class__).lstrip('class <\'').rstrip('>\'')


def print_exception(name, output=sys.stderr):
    """Print less exception info, using in except blocks"""
    assert name
    assert output is sys.stderr or output is sys.stdout
    exc_type, exc_val, exc_tb = sys.exc_info()
    exc_type = str(exc_type).lstrip('class <').rstrip('>')
    sys.stderr.write('%s : %s from :%s\n' % (exc_type, exc_val, name))
    traceback.print_tb(exc_tb, limit=2, file=output)



from threading import Thread as _Thread

class __Flusher(_Thread):
    """Singleton stdout/stderr/stdin flusher for multi-threads"""
    import time
    from sys import stderr as _stderr
    from sys import stdout as _stdout
    from sys import stdin as _stdin
    
    def __init__(self, delay=10, ios=(_stdout, _stderr)):
        _Thread.__init__(self)
        self.daemon = True
        self.__ios = ios
        self.__delay = delay
    
    def run(self):
        while True:
            for each in self.__ios:
                each.flush()
            time.sleep(self.__delay)

__flusher = __Flusher()


def run_stdio_flusher() -> bool:
    """Run singleton global std in/out/err timed flusher"""
    global __flusher
    if __flusher.is_alive():
        return False
    __flusher.start()
    return True



@time_meter(path.basename(__file__))
def test():
    sys.stdout.write(stdtime()+'\n')
    
    class Tester(object):
        def do(self):
            try:
                raise ValueError('This is a testing not really exception!')
            except Exception:
                print_exception(classname(self))
     
    Tester().do()
    
    assert run_stdio_flusher()
    assert not run_stdio_flusher()


if __name__ == '__main__':
    test()



